//
//  NetworkMgr.m
//  AutoRental
//
//  Created by sanzhang on 1/16/14.
//  Copyright (c) 2014 zuche. All rights reserved.
//

#import "NetworkMgr.h"
#import "Reachability.h"
#import "YSDefine.h"
#import "JSONKit.h"
#import "ASIHTTPRequest.h"
#import "ASIFormDataRequest.h"
#import "ASINetworkQueue.h"
#import "NSData+AES256.h"
#import "NetworkMgr+Interface.h"
#import "YSGlobal.h"

@interface NetworkMgr (internal)
{

}
@property (strong) ASINetworkQueue *networkQueue;
@property (strong, readwrite) NSMutableArray  *requestItems;

@end

@implementation NetworkMgr

+ (id)sharedManager
{
    static id sharedManager;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedManager = [[self alloc] init];
    });
    return sharedManager;
}

+ (NSString *)clientID
{
    NSString *g_clientID = [YSGlobal getUID];
    if (g_clientID) {
        return g_clientID;
    }
    return @"";
}

- (id)init
{
    self = [super init];
    self.requestItems = [[NSMutableArray alloc] initWithCapacity:4];
    return self;
}

- (NSString *)generalParams
{
    NSString *result=@"";
    result= [NSString stringWithFormat:@"uid=%@", [NetworkMgr clientID]];
    
    return result;
}

- (void)setupRequest:(ASIFormDataRequest *)request withFormData:(id)data
{
	[[request postBody] setLength:0];
	
	if ([data isKindOfClass:[NSData class]])
    {
		[request appendPostData:data];
	} else if ([data isKindOfClass:[NSString class]]) {
		[request appendPostData:[data dataUsingEncoding:NSUTF8StringEncoding]];
	} else if ([data isKindOfClass:[NSDictionary class]]) {
		//
		if (data && [data isKindOfClass:[NSDictionary class]])
        {
			NSArray *keys=[data allKeys];
			unsigned i, c=[keys count];
			for (i=0; i<c; i++)
			{
				NSString *k=[keys objectAtIndex:i];
				NSString *v=[data objectForKey:k];
				if (k)
                {
					[request setPostValue:v forKey:k];  // TBD
				}
			}
		}
	}
}

- (void)setupRequest:(ASIHTTPRequest *)request withJSONObject:(id)object
{
    NSDictionary *param = (NSDictionary *)object;
	if (![param isKindOfClass:[NSDictionary class]])
	{
		NSLog(@"WARNING: jsonobject no dictionary");
        return;
	}
    
    [[request postBody] setLength:0];
	if ([param objectForKey:@"222"])
	{
		[request appendPostData:[[[param objectForKey:@"111"] JSONString] dataUsingEncoding:NSUTF8StringEncoding]];
	}
}

- (void)cancelRequest:(ASIHTTPRequest *)request
{
    if (request && !request.complete)
    {
        [request clearDelegatesAndCancel];
    }
}

- (void)cancelAsynRequest
{
    [self cancelRequest:self.asynchRequest];
}

- (void)asynchRequestWithFunId:(eYylFuncID)funId delegate:(id)del params:(NSDictionary *)params
{
    if (![[NetworkMgr sharedManager] isReachable])
    {
        return;
    }
    [self cancelRequest:self.asynchRequest];
    ASIHTTPRequest *request = [self buildRequestWithFunId:funId option:params];
    
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    [userInfo setValue:del forKey:kHTTPCallbackDelegate];
    [userInfo setValue:params forKey:kREQUEST_PARAMS];
    [userInfo setValue:[NSString stringWithFormat:@"%d",funId] forKey:kFUN_ID];
    
    [request setUserInfo:userInfo];
    
    self.asynchRequest = request;
    
    [request setDelegate:self];
    [request startAsynchronous];
}
// callback
- (void)requestFinished:(ASIHTTPRequest *)request
{
    request.delegate = [[request userInfo] objectForKey:kHTTPCallbackDelegate];
    [self success:request];
}

- (void)requestFailed:(ASIHTTPRequest *)request
{
    request.delegate = [[request userInfo] objectForKey:kHTTPCallbackDelegate];
    [self failed:request];
}


- (void)clearAllRequest
{
	if (self.asynchRequest)
    {
		[self.asynchRequest clearDelegatesAndCancel];
	}
	
    if (self.formDataRequest)
    {
		[self.formDataRequest clearDelegatesAndCancel];
	}
    
	if (self.networkQueue)
    {
		[self.networkQueue reset];
	}
	
	if (self.delegate)
    {
		[self.delegate didCancelNetwork:self];
	}
}

#pragma mark -
#pragma mark Queue

- (void) requestInQueueWithFunId:(eYylFuncID)funId delegate:(id)del params:(NSDictionary *)params
{
    if (![[NetworkMgr sharedManager] isReachable])
    {
        return;
    }
	if (self.networkQueue == nil)
    {
		[self readyQueueRequest];
	}

    ASIHTTPRequest *request = [self buildRequestWithFunId:funId option:params];
    [request setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:del, kHTTPCallbackDelegate,params,kREQUEST_PARAMS,nil]];
    request.delegate = del;
    
	[self.networkQueue addOperation:request];
}

- (void) readyQueueRequest
{
	if (!self.networkQueue)
    {
		self.networkQueue = [[ASINetworkQueue alloc] init];
	}
	
	[self.networkQueue reset];
	[self.networkQueue setRequestDidFinishSelector:@selector(dataFetchComplete:)];
	[self.networkQueue setRequestDidFailSelector:@selector(dataFetchFailed:)];
	[self.networkQueue setDelegate:self];
    [self.networkQueue setShouldCancelAllRequestsOnFailure:NO];
    [self startQueueRequest];
}

- (void) startQueueRequest
{
	if (self.networkQueue)
    {
		[self.networkQueue go];
	}
}

- (void) cancelQueueRequest
{
	if (self.networkQueue)
    {
		[self.networkQueue cancelAllOperations];
	}
}

- (void) dataFetchComplete:(ASIHTTPRequest *)request
{
	[self success:request];
}

- (void) dataFetchFailed:(ASIHTTPRequest *)request
{
	[self failed:request];
}

#pragma mark - common callback workflow====
- (void) success:(ASIHTTPRequest *)request
{
	if ([request isCancelled] == NO)
    {
        NSString *responseStr = [NSData AES256DecryptWithCiphertextExt:[request responseString]];
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setObject:request.userInfo[kFUN_ID] forKey:kFUN_ID];
        
        if (responseStr/* && ![Utility isEmptyObj:responseStr]*/)
        {
            NSDictionary *responseDict;
            if (IS_OS_5_OR_LATER)
            {
                NSError *error;
                NSData *dataJSON = [responseStr dataUsingEncoding:NSUTF8StringEncoding];
                responseDict = [NSJSONSerialization JSONObjectWithData:dataJSON options:NSJSONReadingMutableLeaves error:&error];
            } else {
                responseDict = [responseStr objectFromJSONString];
            }
            
            [dic setObject:responseDict[API_Result_STATUS] forKey:API_Result_STATUS];
            [dic setObject:responseDict[API_Result_MSG] forKey:API_Result_MSG];
            
            int statusCode = [responseDict[API_Result_STATUS] intValue];
            if (statusCode == 200)
            {
                NSDictionary *resultDict = [responseDict objectForKey:API_Result_RE];
                if ([resultDict isKindOfClass:[NSDictionary class]])  // TBD
                {
                    [dic setObject:resultDict forKey:API_Result_RE];
                    NSLog(@"%@",dic);
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [request.delegate didSuccess:self userInfo:dic]; // TBD
                    });
                } else {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [request.delegate didSuccess:self userInfo:dic]; // TBD
                    });
                }
            } else {
                switch (statusCode)
                {
                    case -910://未登陆。当前请求需登录后访问
                        [self.requestItems addObject:[request.userInfo copy]];
                        
//                        [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationLoginOut
//                                                                            object:@{API_Field_STATUS:@(statusCode),
//                                                                                     kHTTPCallbackDelegate:request.userInfo[kHTTPCallbackDelegate]}];
                        break;
                    case -912:
                        
                        break;
                    case -920:
                        
                        break;
                    case -930://uuid过期
                        NSLog(@"uid no available occur!");
                        [self.requestItems insertObject:[request.userInfo copy] atIndex:0];
                        
//                        [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationNetWorkStatus object:@{API_Field_STATUS:[NSNumber numberWithInt:statusCode]}];
                        break;
                    case -500:
                        
                        break;
                    default:
                        break;
                }
                
                //当发生uuid错误或过期时，不返回网络错误
                if ((statusCode == -930) || (statusCode == -910))
                {
                    return;
                }
                
                // enter failure callback
                NSError *error = [NSError errorWithDomain:NetworkRequestErrorDomain  // TBD
                                                     code:statusCode
                                                 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:responseDict[@"msg"], NSLocalizedDescriptionKey,nil]];
                [dic setObject:error forKey:@"err"];
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    [request.delegate didFail:self userInfo:dic];
                });
            }
        }
        else
        {
            // enter failure callback
            NSError *error = [NSError errorWithDomain:NetworkRequestErrorDomain
                                                 code:400
                                             userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"response json can't parse.", NSLocalizedDescriptionKey,nil]];
            [dic setObject:error forKey:@"err"];

            dispatch_async(dispatch_get_main_queue(), ^{
                [request.delegate didFail:self userInfo:dic];
            });
        }
    }
}

- (void) failed:(ASIHTTPRequest *)request
{
	if ([request isCancelled] == NO)
    {
        NSLog(@"failed enter");
        
		NSMutableDictionary *dic = [NSMutableDictionary dictionary];
//        [dic setObject:request.userInfo[API_PARAM_FUNCTIONID] forKey:API_PARAM_FUNCTIONID];
//        
//        [dic setObject:@"-400" forKey:API_Field_STATUS];
//        [dic setObject:@"服务器繁忙,请稍后再试。" forKey:API_Field_MSG];
        
		NSError *error = [request error];
		if (error)
        {
			[dic setObject:error forKey:@"err"];
		} else {
			error = [NSError errorWithDomain:NetworkRequestErrorDomain
										code:ASIUnKnowError
									userInfo:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"unknown error", nil), NSLocalizedDescriptionKey,nil]];
			[dic setObject:error forKey:@"err"];
		}
		
        dispatch_async(dispatch_get_main_queue(), ^{
            [request.delegate didFail:self userInfo:dic];
        });
	}
}

#pragma mark -test later

-(void)makeRequestWithUrl:(NSString *)urlStr
                   method:(NSString *)method
                     body:(id)object
                  success:(ASIBasicBlock)successBlock
                  failure:(ASIBasicBlock)failureBlock
{
    NSURL *url = [NSURL URLWithString:urlStr];
	__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
    
	[request setCompletionBlock:successBlock];
	[request setFailedBlock:failureBlock];
    
	[request startAsynchronous];
}

- (void)asynchRequestWithURLStr:(NSString *)urlStr
                         method:(NSString *)method
                         header:(NSDictionary *)headers
                        options:(NSDictionary *)params
{
    NSLog(@"asynchRequest enter");
    
    ASIHTTPRequest *request;
    
    if (method && ![[method uppercaseString] isEqualToString:@"GET"])
	{
        NSDictionary *param = (NSDictionary *)params;
        if (![param isKindOfClass:[NSDictionary class]])
        {
            NSLog(@"WARNING: json no dictionary");
            return;
        }
        
        if (0) // raw form data to post
        {
            [self cancelRequest:self.formDataRequest];
            self.formDataRequest = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:urlStr]];
            [self setupRequest:self.formDataRequest withFormData:param];
            request = self.formDataRequest;
        }
        else // json body to post
        {
            [self cancelRequest:self.asynchRequest];
            self.asynchRequest = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:urlStr]];
            [self setupRequest:self.asynchRequest withJSONObject:param];
            request = self.asynchRequest;
        }
        
        [request setTimeOutSeconds:60];
		request.requestMethod = method;//[param objectForKey:kHttpMethod];
	} else  {
        [self cancelRequest:self.asynchRequest];
        self.asynchRequest = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:urlStr]];
        request = self.asynchRequest;
        
        [request setTimeOutSeconds:60];
        request.requestMethod = @"GET";
    }
    
    if (headers && [headers count])
    {
        for(NSString* key in [headers allKeys])
        {
            [request addRequestHeader:key value:[headers objectForKey:key]];
        }
    }
    
    [request setDelegate:self];
    [request startAsynchronous];
}

- (BOOL)isReachable
{
    Reachability *reachability = [Reachability reachabilityForInternetConnection];
    NetworkStatus networkStatus = [reachability currentReachabilityStatus];
    return networkStatus != NotReachable;
}

@end
